﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using LCA.Community.Web.Filters;
using LCA.Community.Web.Models;
using Microsoft.Practices.Unity;
using LCA.Community.DAL.Interfaces;
using LCA.Community.DAL.Model;

namespace LCA.Community.Web.Controllers
{
    /// <summary>
    /// Controller for managing blogs. 
    /// </summary>
    public class BlogController : BaseController
    {
        /// <summary>
        /// Index action showing the blog of a user.
        /// </summary>
        /// <param name="id">User id</param>
        /// <returns>Returns the lists of the posts. One view for registered users. An extended view for the blog owner.</returns>
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(ArgumentException), "BlogNotFound", 2)]
        public ActionResult Index(string id)
        {
            ISocialNetworkElement element;
            var group = GroupsRepository.Get(id);
            
            if (group != null)
            {
                element = MvcApplication.Container.Resolve<GroupViewModel>(new ParameterOverrides { { "group", group } });
                ViewData["owner"] = IsGroupMember(id);
                ViewData["member"] = IsGroupOwner(id);
                ViewData["isuser"] = false;
                return View("Index", element);
            }

            var user = UsersRepository.Get(id);
            if(user != null)
            {
                element = MvcApplication.Container.Resolve<UserViewModel>(new ParameterOverrides { { "user", user } });
                bool owner = IsOwner(id);
                ViewData["owner"] = owner;
                ViewData["friends"] = !owner && IsFriend(id);
                ViewData["isuser"] = true;
                return View("Index", element);
            }
            
            throw new ArgumentException("Element not found.");
        }

        /// <summary>
        /// Shows a page for the owner of the blog to be able to add a new post. Only the owner of a blog can open this page.
        /// </summary>
        /// <param name="id">The group id if it is the blog of a group.</param>
        /// <returns>New post view.</returns>
        [SecurityFilter(SecurityRequisites = "Owner,GroupMember", SolvingActionParameter = "id", ErrorResource = "NoAuthorized")]
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "UserNotFound", 2)]
        public ActionResult NewPost(string id)
        {
            var group = GroupsRepository.Get(id);
            var owner = String.Empty;

            if (group != null)
            {
                ViewData["owner"] = IsGroupOwner(id);
                ViewData["member"] = IsGroupMember(id);
                ViewData["isuser"] = false;
                ViewData["group"] = group;
                owner = id;
            }
            else
            {
                var user = UsersRepository.Get(UserID);

                ViewData["owner"] = true;
                ViewData["friends"] = false;
                ViewData["isuser"] = true;
                ViewData["user"] = user;
                owner = UserID;
            }
            return View("NewPost", new Post() { PartitionKey = owner });
        }

        /// <summary>
        /// Gets the data from the new post form, creates a post and adds it to the users post. Only the owner of the blog can access this action.
        /// </summary>
        /// <param name="id">The id of the owner.</param>
        /// <param name="post">The post to be added.</param>
        /// <returns>Return to the new owner blog page.</returns>
        [ValidateInput(false)]
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityFilter(SecurityRequisites = "Owner,GroupMember", SolvingActionParameter = "id", ErrorResource = "NoAuthorized")]
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "UserNotFound", 2)]
        public ActionResult NewPost(string id, Post post)
        {
            post.RowKey = Guid.NewGuid().ToString();
            post.PartitionKey = id;
            post.Author = UserID;
            post.Date = DateTime.UtcNow;

            PostsRepository.Add(post);

            return RedirectToAction("Index", "Blog", new { id = post.PartitionKey });
        }

        /// <summary>
        /// Shows a view where the owner can edit the selected post.
        /// </summary>
        /// <param name="postID">The post ID</param>
        /// <param name="ownerID">The owner ID</param>
        /// <returns>The edit post view</returns>
        [SecurityFilter(SecurityRequisites = "Owner,GroupMember", SolvingActionParameter = "ownerID", ErrorResource = "NoAuthorized")]
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "PostNotFound", 2)]
        public ActionResult EditPost(string postID, string ownerID)
        {
            var group = GroupsRepository.Get(ownerID);

            if (group != null)
            {
                ViewData["owner"] = IsGroupOwner(ownerID);
                ViewData["member"] = IsGroupMember(ownerID);
                ViewData["isuser"] = false;
                ViewData["group"] = group;
            }
            else
            {
                var user = UsersRepository.Get(UserID);

                ViewData["owner"] = true;
                ViewData["friends"] = false;
                ViewData["isuser"] = true;
                ViewData["user"] = user;
            }

            var post = PostsRepository.Get(postID);
            if (post == null)
                throw new NullReferenceException();

            return View("EditPost", post);
        }

        /// <summary>
        /// Saves the editted info from the selected post.
        /// </summary>
        /// <param name="ownerID">The ownerID</param>
        /// <param name="postID">The post ID</param>
        /// <param name="post">The post information</param>
        /// <returns>The index blog view</returns>
        [ValidateInput(false)]
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityFilter(SecurityRequisites = "Owner,GroupMember", SolvingActionParameter = "ownerID", ErrorResource = "NoAuthorized")]
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "PostNotFound", 2)]
        public ActionResult EditPost(string ownerID, string postID, Post post)
        {
            Post prevPost = PostsRepository.Get(postID);
            prevPost.Body = post.Body;
            prevPost.Title = post.Title;
            prevPost.Tags = post.Tags;
            PostsRepository.Update(prevPost);
            return RedirectToAction("Index", "Blog", new { id = prevPost.PartitionKey });
        }

        /// <summary>
        /// Shows the desired post in detail, with the comments. Shows a different view for the owner, where he can delete comments.
        /// </summary>
        /// <param name="postID">The id of the post.</param>
        /// <returns>The view showing the post.</returns>
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(ArgumentException), "PostNotFound", 2)]
        public ActionResult Article(string postID)
        {
            Post post = PostsRepository.Get(postID);
            if (post == null)
                throw new ArgumentException("Post not found.");

            var group = GroupsRepository.Get(post.Author);
            if (group != null)
            {
                ViewData["owner"] = IsGroupMember(post.Author);
                ViewData["member"] = IsGroupOwner(post.Author);
                ViewData["isuser"] = false;
                ViewData["group"] = group;
            }
            else
            {
                var user = UsersRepository.Get(post.Author);
                bool owner = IsOwner(post.Author);
                ViewData["owner"] = owner;
                ViewData["friends"] = !owner && IsFriend(post.Author);
                ViewData["isuser"] = true;
                ViewData["user"] = user;
            }

            ViewData["postID"] = post.RowKey;
            var viewModel = MvcApplication.Container.Resolve<PostViewModel>(new ParameterOverrides { { "post", post } });
            return View("Article", viewModel);            
        }

        /// <summary>
        /// Add a vote to a post
        /// </summary>
        /// <param name="postID">The post ID.</param>
        /// <param name="userID">The user ID.</param>
        /// <returns>The updated number of votes.</returns>
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "Debe estar registrado.")]
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "PostNotFound", 2)]
        public string VotePost(string postID, string userID)
        {
            if (!PostVotesRepository.UserHasVotedPost(userID, postID))
            {
                PostVote vote = new PostVote(postID, UserID);
                PostVotesRepository.Add(vote);
            }

            return PostVotesRepository.GetPostVotesCount(postID).ToString();
        }

        /// <summary>
        /// Adds a comment to the selected post.
        /// </summary>
        /// <param name="comment">Comment to add.</param>
        /// <returns>ShowComments partial view.</returns>
        [AcceptVerbs(HttpVerbs.Post)]
        [SecurityFilter(SecurityRequisites = "Registered", ErrorResource = "Debe estar registrado.")]
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "PostNotFound", 2)]
        public ActionResult AddComment(Comment comment)
        {
            comment.RowKey = Guid.NewGuid().ToString();
            comment.Date = DateTime.UtcNow;
            var postID = comment.PartitionKey;
            CommentsRepository.Add(comment);
            var comments = CommentViewModel.ConvertListComments(CommentsRepository.GetCommentsByPost(postID));

            return PartialView("ShowComments", comments);
        }

        /// <summary>
        /// Deletes the selected post from the users blog.
        /// </summary>
        /// <param name="postID">The post id.</param>
        /// <returns>Index blog view or index admin view.</returns>
        [ErrorFilter(typeof(Exception), "RequestError", 1)]
        [ErrorFilter(typeof(NullReferenceException), "PostNotFound", 2)]
        public ActionResult DeletePost(string postID)
        {
            Post post = PostsRepository.Get(postID);
            if(post != null && post.Author == UserID)
                PostsRepository.Delete(post);

            return IsAdmin(UserID)
                       ? RedirectToAction("Index", "Admin")
                       : RedirectToAction("Index", "Blog", new { UserID });
        }

        [Dependency]
        public IUsersRepository UsersRepository { get; set; }
        [Dependency]
        public IPostsRepository PostsRepository { get; set; }
        [Dependency]
        public IPostVotesRepository PostVotesRepository { get; set; }
        [Dependency]
        public ICommentsRepository CommentsRepository { get; set; }
    }
}
